// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

#ifndef MANIFEST_MANAGER_H_
#define MANIFEST_MANAGER_H_

#include <stdint.h>
#include <stddef.h>
#include "status/rot_status.h"
#include "manifest.h"


/**
 * Base API for managing a single set of manifests.
 */
struct manifest_manager {
	/**
	 * Activate the pending manifest and discard the active manifest.
	 *
	 * @param manager The manifest manager to update.
	 *
	 * @return 0 if the pending manifest was successfully activated or an error if there no pending
	 * manifest to activate.
	 */
	int (*activate_pending_manifest) (struct manifest_manager *manager);

	/**
	 * Clear the pending manifest region in order to accept new manifest data.
	 *
	 * @param manager The manifest manager for the pending region to clear.
	 * @param size Size of incoming manifest
	 *
	 * @return 0 if the pending manifest region was successfully cleared or an error code.
	 */
	int (*clear_pending_region) (struct manifest_manager *manager, size_t size);

	/**
	 * Write data to the pending manifest region. This data must be written sequentially.
	 *
	 * @param manager The manifest manager for the pending region to write to.
	 * @param data The data that should be written.
	 * @param length The length of the data to write.
	 *
	 * @return 0 if the data was successfully written or an error code.
	 */
	int (*write_pending_data) (struct manifest_manager *manager, const uint8_t *data,
		size_t length);

	/**
	 * After all manifest has been written to the pending area, verify that the region contains a
	 * valid manifest.
	 *
	 * @param manager The manifest manager to use for validation.
	 *
	 * @return 0 if the pending manifest was successfully validated or an error code.
	 */
	int (*verify_pending_manifest) (struct manifest_manager *manager);

	/**
	 * Erase all manifest data from both active and pending regions and revert to state with no
	 * valid manifests.
	 *
	 * @param manager The manifest manager for the manifests to clear.
	 *
	 * @return 0 if the manifests were erased or an error code.
	 */
	int (*clear_all_manifests) (struct manifest_manager *manager);

	int port;						/**< Port identifier for the manager. */
	struct hash_engine *hash;		/**< The hash engine for generating measurement data. */
};


int manifest_manager_init (struct manifest_manager *manager, struct hash_engine *hash);

void manifest_manager_set_port (struct manifest_manager *manager, int port);
int manifest_manager_get_port (struct manifest_manager *manager);

int manifest_manager_get_id_measured_data (struct manifest *active, size_t offset,
	uint8_t *buffer, size_t length, uint32_t *total_len);
int manifest_manager_get_platform_id_measured_data (struct manifest *active, size_t offset,
	uint8_t *buffer, size_t length, uint32_t *total_len);
int manifest_manager_get_manifest_measured_data (struct manifest_manager *manager,
	struct manifest *active, size_t offset, uint8_t *buffer, size_t length, uint32_t *total_len);


#define	MANIFEST_MANAGER_ERROR(code)		ROT_ERROR (ROT_MODULE_MANIFEST_MANAGER, code)

/**
 * Error codes that can be generated by a manifest manager.
 *
 * Note: Commented error codes have been deprecated.
 */
enum {
	MANIFEST_MANAGER_INVALID_ARGUMENT = MANIFEST_MANAGER_ERROR (0x00),					/**< Input parameter is null or not valid. */
	MANIFEST_MANAGER_NO_MEMORY = MANIFEST_MANAGER_ERROR (0x01),							/**< Memory allocation failed. */
	MANIFEST_MANAGER_ACTIVATE_FAILED = MANIFEST_MANAGER_ERROR (0x02),					/**< Pending manifest was not activated. */
	MANIFEST_MANAGER_CLEAR_FAILED = MANIFEST_MANAGER_ERROR (0x03),						/**< The pending region was not cleared. */
	MANIFEST_MANAGER_WRITE_FAILED = MANIFEST_MANAGER_ERROR (0x04),						/**< Data was not written to the pending region. */
	MANIFEST_MANAGER_VERIFY_FAILED = MANIFEST_MANAGER_ERROR (0x05),						/**< An error unrelated to verification occurred. */
	MANIFEST_MANAGER_INVALID_ID = MANIFEST_MANAGER_ERROR (0x06),						/**< The manifest ID is not valid. */
	MANIFEST_MANAGER_NONE_PENDING = MANIFEST_MANAGER_ERROR (0x07),						/**< There is no manifest pending for the operation. */
	MANIFEST_MANAGER_PENDING_IN_USE = MANIFEST_MANAGER_ERROR (0x08),					/**< The pending manifest is actively being used. */
	MANIFEST_MANAGER_NOT_CLEARED = MANIFEST_MANAGER_ERROR (0x09),						/**< Pending region was not cleared before write. */
//	MANIFEST_MANAGER_OUT_OF_SPACE = MANIFEST_MANAGER_ERROR (0x0a),						/**< Not enough room in the pending region for data. */
//	MANIFEST_MANAGER_INCOMPLETE_WRITE = MANIFEST_MANAGER_ERROR (0x0b),					/**< Not all data was written. */
	MANIFEST_MANAGER_HAS_PENDING = MANIFEST_MANAGER_ERROR (0x0c),						/**< A pending manifest is already present. */
	MANIFEST_MANAGER_NO_TASK = MANIFEST_MANAGER_ERROR (0x0d),							/**< No manager command task is running. */
	MANIFEST_MANAGER_TASK_BUSY = MANIFEST_MANAGER_ERROR (0x0e),							/**< The command task is busy performing an operation. */
	MANIFEST_MANAGER_UNSUPPORTED_OP = MANIFEST_MANAGER_ERROR (0x0f),					/**< The requested operation is not supported by the manager. */
	MANIFEST_MANAGER_INCOMPATIBLE = MANIFEST_MANAGER_ERROR (0x10),						/**< The pending manifest is incompatible with the system. */
	MANIFEST_MANAGER_INCOMPLETE_UPDATE = MANIFEST_MANAGER_ERROR (0x11),					/**< The staging flash has not been programmed with all the expected data. */
	MANIFEST_MANAGER_NO_ACTIVE_MANIFEST = MANIFEST_MANAGER_ERROR (0x12),				/**< No active manifest found. */
	MANIFEST_MANAGER_ACTIVE_IN_USE = MANIFEST_MANAGER_ERROR (0x13),						/**< The active manifest is currently being used. */
	MANIFEST_MANAGER_CLEAR_ALL_FAILED = MANIFEST_MANAGER_ERROR (0x14),					/**< Failed to clear the manifest data. */
};


#endif /* MANIFEST_MANAGER_H_ */
